Õppige selgeks Reacti useState hook koos täiustatud optimeerimistehnikate ja parimate praktikatega, et luua globaalselt jõudsaid ja hooldatavaid rakendusi.
React useState: Olekuhook'i optimeerimine ja parimad praktikad
useState hook on Reacti funktsionaalsete komponentide olekuhalduse nurgakivi. Kuigi seda on lihtne kasutada, võib selle ebaõige käsitlemine põhjustada jõudluse kitsaskohti ja ootamatut käitumist, eriti keerukates rakendustes. See juhend pakub põhjalikku ülevaadet useState'i optimeerimistehnikatest ja parimatest praktikatest, tagades, et teie Reacti rakendused on jõudsad, hooldatavad ja skaleeritavad globaalsele publikule.
useState'i põhitõdede mõistmine
Enne optimeerimisse süvenemist vaatame kiirelt üle põhitõed. useState hook võimaldab teil lisada oleku funktsionaalsetele komponentidele. See võtab argumendiks algse oleku väärtuse ja tagastab massiivi, mis sisaldab praegust olekut ja funktsiooni selle uuendamiseks.
Näide:
import React, { useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
return (
<div>
<p>Loendur: {count}</p>
<button onClick={() => setCount(count + 1)}>Suurenda</button>
</div>
);
}
export default MyComponent;
Selles näites hoiab count praegust oleku väärtust ja setCount on funktsioon selle uuendamiseks. Nupule klõpsamine suurendab loendurit.
Levinud lõksud ja jõudlusprobleemid useState'iga
Kuigi useState tundub lihtne, võib see ebaõigel kasutamisel põhjustada jõudlusprobleeme. Siin on mõned levinud lõksud:
- Ebavajalikud uuesti renderdamised: Kõige sagedasem probleem tekib siis, kui komponendid renderdatakse uuesti isegi siis, kui nende propsid ei ole muutunud. See võib juhtuda, kui olekut uuendatakse sageli või kui uuendused käivitavad ebavajalikke uuesti renderdamisi alamkomponentides.
- Otsene oleku muteerimine: Oleku otsene muutmine (nt
state.property = newValue) möödub Reacti uuendusmehhanismist ja võib põhjustada ettearvamatut käitumist. Kasutage alatiuseState'i poolt pakutavat oleku uuendamise funktsiooni. - Keerulised olekuuuendused: Kulukate arvutuste või keerukate teisenduste tegemine oleku uuendamise funktsioonis võib teie rakendust aeglustada.
- Vale algolek: Vale või halvasti initsialiseeritud algoleku pakkumine võib hiljem põhjustada vigu ja ootamatut käitumist.
useState'i optimeerimistehnikad
Nüüd uurime erinevaid optimeerimistehnikaid, et neid probleeme leevendada ja teie Reacti rakenduste jõudlust parandada:
1. Funktsionaalsete uuenduste kasutamine
Kui uuendate olekut selle eelmise väärtuse põhjal, kasutage oleku uuendamise funktsiooni funktsionaalset vormi. See tagab, et töötate kõige ajakohasema olekuga, eriti asünkroonsetes stsenaariumides või kui mitu uuendust on kokku pakitud.
Näide (Vale):
function IncorrectComponent() {
const [count, setCount] = useState(0);
const incrementTwice = () => {
setCount(count + 1);
setCount(count + 1); // Potentsiaalselt vale: tugineb vananenud `count` väärtusele
};
return (
<div>
<p>Loendur: {count}</p>
<button onClick={incrementTwice}>Suurenda kaks korda</button>
</div>
);
}
Näide (Õige):
function CorrectComponent() {
const [count, setCount] = useState(0);
const incrementTwice = () => {
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1); // Õige: kasutab iga uuenduse jaoks eelmist olekut
};
return (
<div>
<p>Loendur: {count}</p>
<button onClick={incrementTwice}>Suurenda kaks korda</button>
</div>
);
}
Õiges näites saab oleku uuendamise funktsioon argumendiks eelmise oleku (prevCount), mis võimaldab teil teha täpseid uuendusi olenemata ajastusest või pakkimisest.
2. Muutumatus on võtmetähtsusega
Ärge kunagi muutke olekut otse. Looge uuendamisel alati uus koopia olekuobjektist või massiivist. See tagab, et React suudab muutusi tõhusalt tuvastada ja käivitada uuesti renderdamisi ainult siis, kui see on vajalik.
Näide (Vale - otsene muteerimine):
function IncorrectObjectComponent() {
const [user, setUser] = useState({ name: 'John', age: 30 });
const updateName = () => {
user.name = 'Jane'; // Otsene muteerimine: vältige seda!
setUser(user); // React ei pruugi muutust tuvastada
};
return (
<div>
<p>Nimi: {user.name}, Vanus: {user.age}</p>
<button onClick={updateName}>Uuenda nime</button>
</div>
);
}
Näide (Õige - muutumatuse kasutamine):
function CorrectObjectComponent() {
const [user, setUser] = useState({ name: 'John', age: 30 });
const updateName = () => {
setUser({ ...user, name: 'Jane' }); // Looge uus objekt uuendatud nimega
};
return (
<div>
<p>Nimi: {user.name}, Vanus: {user.age}</p>
<button onClick={updateName}>Uuenda nime</button>
</div>
);
}
Õiges näites loob laiali laotamise operaator (...) user objekti pinnapealse koopia, tagades, et setUser saab uue objekti ja käivitab uuesti renderdamise.
3. useMemo kasutamine ebavajalike uuesti renderdamiste vältimiseks
useMemo hook'i saab kasutada kulukate arvutuste või objektide loomise tulemuste meeldejätmiseks (vahemällu salvestamiseks). See takistab nende arvutuste ebavajalikku uuesti tegemist iga uuesti renderdamise korral.
Näide:
import React, { useState, useMemo } from 'react';
function ExpensiveCalculationComponent() {
const [count, setCount] = useState(0);
// Simuleerige kulukat arvutust
const expensiveValue = useMemo(() => {
console.log('Tehakse kulukat arvutust...');
let result = 0;
for (let i = 0; i < 100000000; i++) {
result += i;
}
return result;
}, []); // Tühi sõltuvuste massiiv: arvutatakse ainult esmasel renderdamisel
return (
<div>
<p>Loendur: {count}</p>
<p>Kulukas väärtus: {expensiveValue}</p>
<button onClick={() => setCount(count + 1)}>Suurenda loendurit</button>
</div>
);
}
Selles näites arvutatakse expensiveValue ainult üks kord, kui komponent esmakordselt renderdatakse. Järgnevad uuesti renderdamised (mille käivitab count oleku uuendus) kasutavad vahemällu salvestatud väärtust, vältides kulukat arvutust.
4. useCallback sündmuste käsitlejate meeldejätmiseks
Kui edastate sündmuste käsitleja funktsioone propsidena alamkomponentidele, kasutage funktsiooni meeldejätmiseks useCallback'i. See takistab alamkomponendi ebavajalikku uuesti renderdamist, kui vanemkomponent uuesti renderdatakse.
Näide:
import React, { useState, useCallback } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
// Jätke meelde suurendamise funktsioon useCallback'i abil
const increment = useCallback(() => {
setCount(count + 1);
}, [count]); // Sõltuvuste massiiv: looge funktsioon uuesti ainult siis, kui 'count' muutub
return (
<div>
<p>Loendur: {count}</p>
<ChildComponent onClick={increment} />
</div>
);
}
// Eeldades, et ChildComponent on meelde jäetud React.memo abil
const ChildComponent = React.memo(({ onClick }) => {
console.log('ChildComponent renderdati uuesti!');
return <button onClick={onClick}>Suurenda (laps)</button>;
});
Selles näites jätab useCallback meelde increment funktsiooni, takistades ChildComponent'i uuesti renderdamist, välja arvatud juhul, kui count väärtus (ja seega ka increment funktsioon) muutub.
5. Oleku jaotamine väiksemateks, sõltumatuteks osadeks
Kui teie komponendil on suur ja keeruline olekuobjekt, kaaluge selle jaotamist väiksemateks, sõltumatuteks olekuosadeks, kasutades mitut useState hook'i. See võimaldab Reactil uuendada ainult neid konkreetseid komponendi osi, mis sõltuvad muutunud olekust, vähendades ebavajalikke uuesti renderdamisi.
Näide (Enne - suur olekuobjekt):
function LargeStateComponent() {
const [state, setState] = useState({
name: 'John',
age: 30,
city: 'New York',
country: 'USA'
});
const updateName = () => {
setState({ ...state, name: 'Jane' });
};
const updateAge = () => {
setState({ ...state, age: 31 });
};
return (
<div>
<p>Nimi: {state.name}</p>
<p>Vanus: {state.age}</p>
<p>Linn: {state.city}</p>
<p>Riik: {state.country}</p>
<button onClick={updateName}>Uuenda nime</button>
<button onClick={updateAge}>Uuenda vanust</button>
</div>
);
}
Näide (Pärast - oleku jaotamine):
function SplitStateComponent() {
const [name, setName] = useState('John');
const [age, setAge] = useState(30);
const [city, setCity] = useState('New York');
const [country, setCountry] = useState('USA');
const updateName = () => {
setName('Jane');
};
const updateAge = () => {
setAge(31);
};
return (
<div>
<p>Nimi: {name}</p>
<p>Vanus: {age}</p>
<p>Linn: {city}</p>
<p>Riik: {country}</p>
<button onClick={updateName}>Uuenda nime</button>
<button onClick={updateAge}>Uuenda vanust</button>
</div>
);
}
Jaotades oleku eraldi useState hook'idesse, käivitab name'i uuendamine uuesti renderdamise ainult nendes komponendi osades, mis sõltuvad name olekust, parandades jõudlust.
6. Laisk initsialiseerimine kuluka algoleku jaoks
Kui algoleku arvutamine on arvutuslikult kulukas, kasutage useState'i laiska initsialiseerimise funktsiooni. Selle asemel, et anda algväärtus otse, saate edastada funktsiooni, mis tagastab algväärtuse. See funktsioon käivitatakse ainult üks kord, esmasel renderdamisel.
Näide:
import React, { useState } from 'react';
function LazyInitializationComponent() {
// Kulukas funktsioon algoleku arvutamiseks
const expensiveInitialState = () => {
console.log('Arvutatakse algolekut...');
let result = 0;
for (let i = 0; i < 100000000; i++) {
result += i;
}
return result;
};
const [value, setValue] = useState(expensiveInitialState);
return (
<div>
<p>Väärtus: {value}</p>
<button onClick={() => setValue(value + 1)}>Suurenda</button>
</div>
);
}
Selles näites käivitatakse expensiveInitialState funktsioon ainult üks kord, kui komponent paigaldatakse. Kui edastaksite expensiveInitialState() tulemuse otse useState'ile, käivitataks see iga uuesti renderdamise korral, kuigi algolekut on vaja arvutada ainult üks kord.
7. useReducer'i kasutamine keerulise olekuloogika jaoks
Komponentide puhul, millel on keeruline olekuloogika, mis hõlmab mitut alamväärtust või keerulisi olekusiirdeid, kaaluge useState'i asemel useReducer hook'i kasutamist. useReducer pakub struktureeritumat ja ennustatavamat viisi oleku haldamiseks, eriti seotud olekuuuendustega tegelemisel.
Näide:
import React, { useReducer } from 'react';
// Määratlege redutseerija funktsioon
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
case 'RESET':
return { ...state, count: 0 };
default:
return state;
}
};
// Algolek
const initialState = { count: 0 };
function ReducerComponent() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Loendur: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Suurenda</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Vähenda</button>
<button onClick={() => dispatch({ type: 'RESET' })}>Lähtesta</button>
</div>
);
}
Selles näites haldab useReducer count olekut ja pakub dispatch funktsiooni olekuuuenduste käivitamiseks erinevate toimingute põhjal. See lähenemine on eriti kasulik mitme seotud uuenduse või keerukate üleminekutega oleku haldamisel.
8. React.memo funktsionaalsete komponentide meeldejätmiseks
Mähkige oma funktsionaalsed komponendid React.memo'sse, et vältida uuesti renderdamisi, kui propsid ei ole muutunud. React.memo teostab propside pinnapealse võrdluse ja renderdab komponendi uuesti ainult siis, kui propsid on erinevad.
Näide:
import React from 'react';
// Jätke komponent meelde React.memo abil
const MyMemoizedComponent = React.memo(({ data }) => {
console.log('MyMemoizedComponent renderdati uuesti!');
return <p>Andmed: {data}</p>;
});
React.memo võib oluliselt parandada jõudlust, eriti sageli uuesti renderdatavate komponentide puhul, millel on staatilised või harva muutuvad propsid.
useState'i parimad praktikad globaalses kontekstis
Reacti rakenduste arendamisel globaalsele publikule arvestage nende täiendavate parimate tavadega:
- Rahvusvahelistamine (i18n): Kasutage tõlgete haldamiseks ja rakenduse kasutajaliidese kohandamiseks erinevatele keeltele ja lokaatidele teeki nagu
react-intlvõii18next. Praeguse lokaadiga seotud olekut tuleks hoolikalt hallata, et tagada teksti ja numbrite järjepidev ja korrektne kuvamine. Näiteks kuupäevad, valuutad ja numbrivormingud on maailmas väga erinevad. - Lokaliseerimine (l10n): Andmete kuvamisel arvestage erinevate kultuuriliste tavadega. Näiteks kuupäevavormingud on erinevad (MM/DD/YYYY vs DD/MM/YYYY) ja valuutasümbolid on igas riigis erinevad (€, $, ¥). Nende seadetega seotud olek peaks olema lokaliseeritud.
- Paremalt-vasakule (RTL) paigutused: Tagage, et teie rakendus toetab RTL-keeli nagu araabia ja heebrea keel. Kasutage CSS-i loogilisi omadusi (nt
margin-inline-startasemelmargin-left) ja teeke nagurtlcsspaigutuse peegeldamise haldamiseks. Hallake paigutuse suunda vajadusel olekuga. - Ajavööndid: Kuupäevade ja kellaaegadega tegelemisel olge teadlik ajavöönditest. Kasutage ajavööndi teisenduste haldamiseks ja aegade kuvamiseks kasutaja kohalikus ajavööndis teeki nagu
moment-timezonevõidate-fns-timezone. Kasutaja praegust ajavööndit saab salvestada olekusse ja uuendada vastavalt nende asukohale. - Juurdepääsetavus (a11y): Kujundage oma rakendus juurdepääsetavust silmas pidades, järgides WCAG juhiseid. Tagage, et teie komponendid on kasutatavad puuetega inimestele, sealhulgas neile, kes kasutavad ekraanilugejaid või abitehnoloogiaid. Näiteks veenduge, et kõigil vormielementidel on sildid ja pakkuge piltidele alternatiivset teksti. Kaaluge linteri nagu eslint-plugin-jsx-a11y kasutamist levinud juurdepääsetavusprobleemide tabamiseks.
Praktilised näited ja kasutusjuhud
Vaatame mõningaid praktilisi näiteid, kuidas neid optimeerimistehnikaid reaalsetes stsenaariumides rakendada:
1. Otsingukomponendi optimeerimine
Kujutage ette otsingukomponenti, mis filtreerib suurt elementide loendit kasutaja sisendi põhjal. Selle komponendi optimeerimiseks saate kasutada useMemo't filtreeritud loendi meeldejätmiseks ja useCallback'i otsingukäsitleja meeldejätmiseks.
import React, { useState, useMemo, useCallback } from 'react';
function SearchComponent({ items }) {
const [searchTerm, setSearchTerm] = useState('');
// Jätke meelde filtreeritud loend
const filteredItems = useMemo(() => {
console.log('Filtreeritakse elemente...');
return items.filter(item =>
item.toLowerCase().includes(searchTerm.toLowerCase())
);
}, [items, searchTerm]);
// Jätke meelde otsingukäsitleja
const handleSearch = useCallback(event => {
setSearchTerm(event.target.value);
}, []);
return (
<div>
<input type="text" placeholder="Otsi..." onChange={handleSearch} />
<ul>
{filteredItems.map(item => (
<li key={item}>{item}</li>
))}
</ul>
</div>
);
}
Selles näites arvutatakse filteredItems uuesti ainult siis, kui items või searchTerm muutub. handleSearch funktsioon on meelde jäetud, vältides alamkomponentide ebavajalikke uuesti renderdamisi.
2. Vormikomponendi optimeerimine
Vormid hõlmavad sageli mitut olekuuuendust ja valideerimist. Vormikomponendi optimeerimiseks kasutage useReducer'it vormi oleku haldamiseks ja useCallback'i vormi esitamise käsitleja meeldejätmiseks.
import React, { useReducer, useCallback } from 'react';
// Määratlege redutseerija funktsioon
const formReducer = (state, action) => {
switch (action.type) {
case 'UPDATE_FIELD':
return { ...state, [action.field]: action.value };
case 'SUBMIT':
// Tehke valideerimine siin
return state;
default:
return state;
}
};
// Algolek
const initialFormState = {
name: '',
email: '',
message: ''
};
function FormComponent() {
const [state, dispatch] = useReducer(formReducer, initialFormState);
// Jätke meelde vormi esitamise käsitleja
const handleSubmit = useCallback(event => {
event.preventDefault();
dispatch({ type: 'SUBMIT' });
console.log('Vorm esitatud:', state);
}, [state]);
const handleChange = (event) => {
dispatch({ type: 'UPDATE_FIELD', field: event.target.name, value: event.target.value });
};
return (
<form onSubmit={handleSubmit}>
<label>
Nimi:
<input type="text" name="name" value={state.name} onChange={handleChange} />
</label>
<label>
E-post:
<input type="email" name="email" value={state.email} onChange={handleChange} />
</label>
<label>
Sõnum:
<textarea name="message" value={state.message} onChange={handleChange} />
</label>
<button type="submit">Esita</button>
</form>
);
}
Selles näites haldab useReducer vormi olekut ja useCallback jätab meelde handleSubmit funktsiooni. See aitab parandada vormikomponendi jõudlust, eriti keeruliste valideerimiste või asünkroonsete operatsioonidega tegelemisel.
Kokkuvõte
useState hook on võimas tööriist oleku haldamiseks funktsionaalsetes Reacti komponentides. Mõistes selle nüansse ja rakendades selles juhendis käsitletud optimeerimistehnikaid, saate luua jõudsaid, hooldatavaid ja skaleeritavaid Reacti rakendusi globaalsele publikule. Ärge unustage eelistada muutumatust, jätta meelde kulukad arvutused ja sündmuste käsitlejad, jaotada olek vajadusel väiksemateks osadeks ja kaaluda useReducer'i kasutamist keerulise olekuloogika jaoks. Pidage alati meeles oma rakenduse globaalset konteksti, arvestades i18n, l10n, RTL paigutusi, ajavööndeid ja juurdepääsetavust. Neid parimaid tavasid järgides saate tagada, et teie Reacti rakendused pole mitte ainult kiired ja tõhusad, vaid ka juurdepääsetavad ja kasutatavad kasutajatele üle kogu maailma.
Lisalugemist
- Reacti dokumentatsioon: https://reactjs.org/docs/hooks-state.html
- useReducer Hook: https://reactjs.org/docs/hooks-reference.html#usereducer
- useMemo Hook: https://reactjs.org/docs/hooks-reference.html#usememo
- useCallback Hook: https://reactjs.org/docs/hooks-reference.html#usecallback
- React.memo: https://reactjs.org/docs/react-api.html#reactmemo